#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <stdlib.h>
#include <cassert>

const std::string pathname = ".";
const int proj_id = 666;
const int shm_size = 4096;

#define CREATER 0
#define USER 1

class smart_init
{
public:
    smart_init(int type)
    {
        // 获取共享内存
        assert(type == CREATER || type == USER);
        if (type == CREATER)
            _shmid = creatShm(getKey());
        else if (type == USER)
            _shmid = searchShm(getKey());

        _type = type;

        // 与共享内存建立联系
        _shm_addr = attachShm(_shmid);
    }

    ~smart_init()
    {
        // 与共享内存断开联系
        detachShm(_shm_addr);

        if (_type == CREATER)
        {
            remoteShm(_shmid);
        }
    }

    void *get_shmaddr()
    {
        return _shm_addr;
    }

private:
    key_t getKey();
    int creatShm(key_t k);
    int searchShm(key_t k);
    int getShm(key_t k, int flag);
    void *attachShm(int shmid);
    void detachShm(const void *shmaddr);
    void remoteShm(int shmid);

private:
    int _type;
    int _shmid;
    void *_shm_addr;
};

std::string toHex(int n)
{
    char buf[64] = {0};
    snprintf(buf, sizeof(buf), "0x%x", n);
    return std::string(buf);
}

key_t smart_init::getKey()
{
    key_t k = ftok(pathname.c_str(), proj_id);
    if (k == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
    return k;
}

int smart_init::getShm(key_t k, int flag)
{
    int shmid = shmget(k, shm_size, flag);
    if (shmid == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(2);
    }
    return shmid;
}

int smart_init::creatShm(key_t k)
{
    umask(0);
    return getShm(k, IPC_CREAT | IPC_EXCL | 0666);
}

int smart_init::searchShm(key_t k)    
{
    umask(0);
    return getShm(k, 0666);
}

void *smart_init::attachShm(int shmid)
{
    void *shm_ptr = shmat(shmid, nullptr, 0);
    if (shm_ptr == (void *)-1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(3);
    }
    return shm_ptr;
}

void smart_init::detachShm(const void *shmaddr)
{
    int ret = shmdt(shmaddr);
    if (ret == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(4);
    }
}

void smart_init::remoteShm(int shmid)
{
    int ret = shmctl(shmid, IPC_RMID, nullptr);
    if (ret == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(5);
    }
}

/* key_t getKey()
{
    key_t k = ftok(pathname.c_str(), proj_id);
    if (k == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
    return k;
}

int getShm(key_t k, int flag)
{
    int shmid = shmget(k, shm_size, flag);
    if (shmid == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(2);
    }
    return shmid;
}

int creatShm(key_t k)
{
    umask(0);
    return getShm(k, IPC_CREAT | IPC_EXCL | 0666);
}

int searchShm(key_t k)
{
    umask(0);
    return getShm(k, IPC_CREAT | 0666);
}

void *attachShm(int shmid)
{
    void *shm_ptr = (char *)shmat(shmid, nullptr, 0);
    if (shm_ptr == (void *)-1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(3);
    }
    return shm_ptr;
}

void detachShm(const void *shmaddr)
{
    int ret = shmdt(shmaddr);
    if (ret == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(4);
    }
}

void remoteShm(int shmid)
{
    int ret = shmctl(shmid, IPC_RMID, nullptr);
    if (ret == -1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(5);
    }
} */
